from client.utils.enum import Enum
from server.sessionstuff.player import Role
from networking.ganet.network import message
from server.sessionstuff.webentities.unit_netmanager import UnitNetManager
from server.sessionstuff.webentities.tower_netmanager import TowerNetManager
import __builtin__


class Phase(Enum):
    PREPARE = 1
    FIGHT = 2

PREP_TIME = 20.0
FIGHT_TIME = 60.0
GRACE_PERIOD = 5.0
GAME_OVER = 10
BROADCAST_INTERVAL = 0.1
LIFES = 25
ROUNDS = 10

class Session():
    def __init__(self, ID, creator):
        self.ID = ID
        self.creator = creator
        self.attacker = creator
        self.defender = 0
        self.unitmanager = 0
        self.towermanager = 0
        self.phase = Phase.FIGHT
        self.gracep = False
        self.pre_phase = False
        self.round = 0
        self.lifes = LIFES
        self.game_over = -100
        self.phasecounter = PREP_TIME
        self.gracetimer = GRACE_PERIOD
        self.broadcasttimer = 0
        self.started = False
        print "set player " + str(creator.peer.addr[1]) + " as attacker"

    def is_role_free(self):
        if self.attacker == 0 or self.defender == 0:
            return True
        return False

    def pl_joins_session(self, pl):
        if self.defender == 0:
            self.defender = pl
            print "set player " + str(pl.peer.addr[1]) + " as defender"
        else:
            self.attacker = pl
            print "set player " + str(pl.peer.addr[1]) + " as attacker"

    def start_session(self):
        self.attacker.init_session(self, Role.ATTACKER)
        self.defender.init_session(self, Role.DEFENDER)

        self.unitmanager = UnitNetManager(self.attacker)
        self.towermanager = TowerNetManager(self.defender)
        self.attacker.manager = self.unitmanager
        self.defender.manager = self.towermanager

        self.started = True
        self._broadcast_settings()

    def update(self, dt):
        if self.game_over > 0:
            self.game_over-=dt
        if -10 < self.game_over <= 0:
            __builtin__.base.sessionmanager.session_finished(self.ID)
        if not self.started:
            return
        self.phasecounter -= dt
        if self.phasecounter <= 0:
            self.update_gracep(dt)
        elif self.phase == Phase.FIGHT and len(self.attacker.manager.units) == 0:
            self.update_gracep(dt)
        if self.gracep:
            return
        if self.phase == Phase.PREPARE:
            self.update_prepare(dt)
        elif self.phase == Phase.FIGHT:
            self.update_fight(dt)

    def update_gracep(self, dt):
        if self.phasecounter > 0:
            self.phasecounter = 0
        if self.gracetimer == GRACE_PERIOD:
            self._grace_period()
        self.gracetimer -= dt
        if self.gracetimer <= GRACE_PERIOD/4 and not self.pre_phase:
            self._pre_phase()
        if self.gracetimer <= 0:
            self._switch_phase()

    def update_prepare(self, dt):
        return

    def update_fight(self, dt):
        self.unitmanager.update(dt)
        self.towermanager.update(dt)
        self.broadcasttimer += dt
        if self.broadcasttimer >= BROADCAST_INTERVAL:
            self.broadcasttimer -= BROADCAST_INTERVAL
            self.broadcast_unitposition()
            #self.broadcast_projectileposition()

    def _switch_phase(self):
        self.gracetimer = GRACE_PERIOD
        self.pre_phase = False
        self.gracep = False
        print "switchy"
        if self.phase == Phase.FIGHT:
            self._phase_prepare()
        else:
            self._phase_fight()

    def _grace_period(self):
        print "GRACE PERIOD"
        self.gracep = True
        if self.phase == Phase.FIGHT and self.round == ROUNDS:
            self._game_over(Role.DEFENDER)
            return
        enc = self._prep_msg()
        enc.write_string("grace_period")
        self._send_message(enc.get_message())
        if self.phase == Phase.PREPARE:
            self._save_placed()

    def _pre_phase(self):
        print "LAST ACTIONS"
        self.pre_phase = True
        if self.phase == Phase.PREPARE:
            self._before_fight()
        else:
            self._before_prepare()

    def _before_fight(self):
        self._broadcast_lists()

    def _before_prepare(self):
        self.round+= 1
        self.towermanager.destroy_all_projectiles()
        self._restore_placed()

    def _phase_fight(self):
        print "FIGHT"
        self.phase = Phase.FIGHT
        self.phasecounter = FIGHT_TIME
        self.broadcasttimer = 0
        enc = self._prep_msg()
        enc.write_string("phase_fight")
        self._send_message(enc.get_message())

    def _phase_prepare(self):
        print "PREPARE"
        self.phase = Phase.PREPARE
        self.phasecounter = PREP_TIME
        enc = self._prep_msg()
        enc.write_string("phase_prepare")
        self._send_message(enc.get_message())

    def remove_life(self):
        self.lifes -= 1
        self._broadcast_lifes()
        if self.lifes <= 0:
            self._game_over(Role.ATTACKER)

    def _game_over(self, player):
        self._broadcast_winner(player)
        self.started = False
        self.game_over = GAME_OVER

    def broadcast_unitposition(self):
        enc = self._prep_msg()
        enc.write_string("update_position")
        for unit in self.attacker.manager.units:
            enc.write_float(unit.pos.x)
            enc.write_float(unit.pos.y)
        self._send_message(enc.get_message())

    def broadcast_projectileposition(self):
        if len(self.defender.manager.projectiles) == 0:
            return
        enc = self._prep_msg()
        enc.write_string("update_projectileposition")
        for p in self.defender.manager.projectiles:
            enc.write_float(p.pos.x)
            enc.write_float(p.pos.y)
        self._send_message(enc.get_message())

    def _restore_placed(self):
        print "restoring placed units"
        self.unitmanager.restore_units()
        self.towermanager.restore_towers()
        self.attacker.update_placed()
        self.defender.update_placed()

    def _save_placed(self):
        print "saving placed units"
        self.unitmanager.save_units()
        self.towermanager.save_towers()

    def _broadcast_lists(self):
        print "broadcasting all units"
        enc = self._prep_msg()
        enc.write_string("update_units")
        enc = self.attacker.encode_list(enc)
        self._send_message(enc.get_message())
        enc = self._prep_msg()
        enc.write_string("update_towers")
        enc = self.defender.encode_list(enc)
        self._send_message(enc.get_message())

    def _broadcast_settings(self):
        enc = self._prep_msg()
        enc.write_string("settings")
        enc.write_float(BROADCAST_INTERVAL)
        enc.write_int(PREP_TIME)
        enc.write_int(FIGHT_TIME)
        enc.write_int(GRACE_PERIOD)
        enc.write_int(ROUNDS)
        enc.write_int(LIFES)
        self._send_message(enc.get_message())

    def _send_message(self, msg):
        #muellhalde.send_message(msg)
        self.defender.send_message(msg)
        self.attacker.send_message(msg)

    def _prep_msg(self):
        enc = message.MessageEncoder()
        enc.reset()
        #enc.write_string("client")
        #enc.write_int(self.role)
        return enc

    def get_role(self, i):
        if i == Role.ATTACKER:
            return self.attacker

        return self.defender

    def place_unit(self, dec):
        if self.phase == Phase.PREPARE:
            target = self.get_role(dec.read_int())
            target.place_unit(dec)

    def place_warpzone(self, dec):
        if self.phase == Phase.PREPARE:
            target =self.get_role(dec.read_int())
            target.place_warpzone(dec)

    def destroy_unit(self, ind):
        enc = self._prep_msg()
        enc.write_string("destroy_unit")
        enc.write_int(ind)
        self._send_message(enc.get_message())

    def destroy_tower(self, ind):
        enc = self._prep_msg()
        enc.write_string("destroy_tower")
        enc.write_int(ind)
        self._send_message(enc.get_message())

    def place_tower(self, dec):
        if self.phase == Phase.PREPARE:
            target = self.get_role(dec.read_int())
            target.place_tower(dec)

    def shoot_projectile(self, name, pos, tar, ind):
        enc = self._prep_msg()
        enc.write_string("shoot_projectile")
        enc.write_string(name)
        enc.write_float(pos[0])
        enc.write_float(pos[1])
        enc.write_string(tar)
        enc.write_int(ind)
        self._send_message(enc.get_message())

    def remove_projectile(self, ind):
        enc = self._prep_msg()
        enc.write_string("remove_projectile")
        enc.write_int(ind)
        self._send_message(enc.get_message())

    def upgrade(self, dec):
        if self.phase == Phase.PREPARE:
            target = self.get_role(dec.read_int())
            target.upgrade(dec)

    def select(self, dec):
        if self.phase == Phase.PREPARE:
            target = self.get_role(dec.read_int())
            target.select(dec)

    def broadcast_unitdestination(self, tower, pos):
        enc = self._prep_msg()
        enc.write_string("update_unitdestination")
        enc.write_int(self.unitmanager.units.index(tower))
        enc.write_float(pos[0])
        enc.write_float(pos[1])
        self._send_message(enc.get_message())

    def _broadcast_lifes(self):
        enc = self._prep_msg()
        enc.write_string("update_lifes")
        enc.write_int(self.lifes)
        self._send_message(enc.get_message())

    def _broadcast_winner(self, player):
        enc = self._prep_msg()
        enc.write_string("game_over")
        if player == Role.ATTACKER:
            enc.write_string("attacker")
        else:
            enc.write_string("defender")
        self._send_message(enc.get_message())
